#pragma once
#include "CDXBuffer.h"
#include "CDXEffect.h"
#include "CResourceLibrary.h"
#ifndef __SWIG__
#include "CDXPrefixSum.h"
#include <D3DX10math.h>
#include <map>
#endif
#define MAX_NUM_TEXCOORD 8


#ifdef __SWIG__
%include <typemaps.i>
%include "mui_typemap.i"

%apply SWIGTYPE** OUTPUT { ID3D11UnorderedAccessView** ppUnorderAccessView};
%apply SWIGTYPE** OUTPUT { ID3D11ShaderResourceView** ppShaderResourceView};
%apply SWIGTYPE** OUTPUT { ID3D11RenderTargetView** ppRenderTargetView};
%apply SWIGTYPE** OUTPUT { D3D11_INPUT_ELEMENT_DESC** layout};
%apply SWIGTYPE** OUTPUT { CDXBuffer** ppBuffer};
%apply SWIGTYPE** OUTPUT { ID3D11Buffer** ppVertexBuffers, UINT* Strides, UINT* Offsets};
%apply UINT& OUTPUT {UINT& nElem};
%apply UINT* OUTPUT {UINT* numBuffers};

#endif










class CDXEffectLibrary;
class CDXPrefixSum;
class CDXGeometry : public CDXBase, public CRefCount
{
#ifndef __SWIG__
public:
	struct LayoutMapKey
	{
		ID3DX11Effect* pEffect;
		UINT techIdx;
		UINT passIdx;
	};
#endif 
protected:
	std::map<LayoutMapKey, ID3D11InputLayout*> m_pLayoutMap;
	HRESULT ClearLayoutMap();
public:
	CDXGeometry(CDXDevice* pDevice);
	virtual ~CDXGeometry();
	virtual HRESULT GetInputLayoutDesc(D3D11_INPUT_ELEMENT_DESC** layout, UINT& nElem) = 0;
	virtual HRESULT GetNumVertexBuffers(UINT* numBuffers) = 0;
	virtual HRESULT GetVertexBuffers(ID3D11Buffer** ppVertexBuffers, UINT* Strides, UINT* Offsets) = 0;
	virtual HRESULT GetIndexBuffer(ID3D11Buffer** pIndexBuffer) { return E_NOT_SUFFICIENT_BUFFER;};
	virtual HRESULT GetIndexCount(UINT& idxCount) {return E_NOTIMPL;};
	virtual D3D11_PRIMITIVE_TOPOLOGY GetPrimitiveTopology() { return D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST;};
	virtual HRESULT GetInputLayout(ID3DX11Effect* pEffect, UINT techIdx, UINT passIdx, ID3D11InputLayout** ppLayout);
};




enum VBType
{
	VB_POSITION,
	VB_NORMAL,
	VB_COLOR,
	VB_TEXCOORD0, 
	VB_TEXCOORD1,
	VB_TEXCOORD2,
	VB_TEXCOORD3,
	VB_TEXCOORD4,
	VB_TEXCOORD5,
	VB_TEXCOORD6,
	VB_TEXCOORD7
};
class CDXPointCloud : public CDXGeometry
{
private:

protected:
	CDXBuffer* m_pVBPositionBuf;
	CDXBuffer* m_pVBNormalBuf;
	CDXBuffer* m_pVBColorBuf;
	CDXBuffer* m_pVBTexcoordBuf[MAX_NUM_TEXCOORD];

	UINT m_nValidVertex;
protected:
	virtual HRESULT _CreateVertexBuffer(CDXBuffer** ppCBuffer, UINT szBuf, UINT szElem, UINT nElem, D3D11_SUBRESOURCE_DATA* pInitData = NULL); 

public:
	CDXPointCloud(CDXDevice* pDevice);
	virtual ~CDXPointCloud();
	virtual UINT GetVertexPositionStride();
	virtual UINT GetVertexNormalStride();
	virtual UINT GetVertexColorStride();
	virtual UINT GetVertexTexcoordStride(UINT idx);

	virtual HRESULT GetVertexNumber(UINT& nVertex);
	virtual HRESULT GetValidVertexNumber(UINT& nVertex);
	virtual HRESULT ResizeVertexBuffer(UINT nVertex, BOOL bKeepBigger = TRUE);
	virtual HRESULT SetVertexPosition(const float* pPositionBuf, UINT nVertex);
	virtual HRESULT SetVertexNormal(const float* pNormalBuf, UINT nVertex);
	virtual HRESULT SetVertexColor(const UCHAR* pColorBuf, UINT nVertex);
	virtual HRESULT SetVertexTexcoord(const float* pTexcoordBuf, UINT idx, UINT nVertex);
	virtual HRESULT GetVertexBuffer(VBType enumBuf, CDXBuffer** ppBuffer, BOOL bCreatIfNULL = TRUE);

	virtual HRESULT ReleaseVertexBuffer(VBType enumBuf);
	virtual HRESULT CreateVertexBuffer(VBType enumBuf, UINT nVertex, const void* pInitData);

	virtual HRESULT ComputeVertexNormal();

	//overwrite CDXGeometry
	virtual HRESULT GetInputLayoutDesc(D3D11_INPUT_ELEMENT_DESC** layout, UINT& nElem);
	virtual HRESULT GetNumVertexBuffers(UINT* numBuffers);
	virtual HRESULT GetVertexBuffers(ID3D11Buffer** ppVertexBuffers, UINT* Strides, UINT* Offsets);
	virtual D3D11_PRIMITIVE_TOPOLOGY GetPrimitiveTopology() { return D3D11_PRIMITIVE_TOPOLOGY_POINTLIST;};
};

class CDXMesh : public CDXPointCloud
{

public:
#ifndef __SWIG__
#pragma pack(push, 1)
	struct IndexedEdge
	{
		UINT orgIdx;
		UINT iStart;
		UINT iEnd;
	};
#pragma pack(pop)
	static int compare_IndexedEdge (const void * a, const void * b);
#endif

private:
	CDXPrefixSum* m_pPrefixSum;

	CDXBuffer* m_pTmpCountBuf;

	CDXBuffer* m_pVBPreEdgeIndexBuf;
	CDXBuffer* m_pVBPreEdgeIndexDuplicateBuf;
	CDXBuffer* m_pVBPreEdgeIndexDuplicateSumBuf;

protected:
	

	CDXBuffer* m_pVBTangentBuf; //include Binormal & Tangent
	CDXBuffer* m_pIBIndexBuf;
	UINT m_nValidIndex;

	CDXBuffer* m_pVBVertex2FaceBuf;
	CDXBuffer* m_pVBVertex2FaceCountBuf;
	CDXBuffer* m_pVBVertex2FaceCountSumBuf;

	CDXBuffer* m_pVBEdgeIndexBuf;

	CDXBuffer* m_pVBVertex2EdgeBuf;
	CDXBuffer* m_pVBVertex2EdgeCountBuf;
	CDXBuffer* m_pVBVertex2EdgeCountSumBuf;

	CDXBuffer* m_pVBFace2EdgeBuf;
	CDXBuffer* m_pVBEdge2FaceBuf;
	CDXBuffer* m_pVBEdge2FaceCountBuf;
	CDXBuffer* m_pVBEdge2FaceCountSumBuf;
protected:
	CDXEffectLibrary* m_pEffectLibrary;
	
protected:	
	virtual HRESULT _ReleaseResource();
	virtual HRESULT _InitEffectLibrary();

	virtual HRESULT _CreateIndexBuffer(CDXBuffer** ppCDXBuffer, UINT szBuf, UINT szElem, UINT nElem, D3D11_SUBRESOURCE_DATA* pInitData = NULL);
	virtual HRESULT _CreateV2FBuffer(CDXBuffer** ppCDXBuffer, UINT szBuf, UINT szElem, UINT nElem, BOOL bStructured, D3D11_SUBRESOURCE_DATA* pInitData = NULL);
	virtual HRESULT _GenerateConnectedBuffers();
	virtual HRESULT _GenerateVertex2FaceBuffers();
	virtual HRESULT _GenerateEdgeBuffers();

	virtual HRESULT _FillVertex2FaceCountBuffer();
	virtual HRESULT _FillVertex2FaceCountSumBuffer();
	virtual HRESULT _FillVertex2FaceBuffer();

	virtual HRESULT _FillPreEdgeIndexBuffer();
	virtual HRESULT _SortPreEdgeIndexBuffer();
	virtual HRESULT _FillPreEdgeIndexDuplicateCountBuffer();
	virtual HRESULT _FillPreEdgeIndexDuplicateCountSumBuffer();
	virtual HRESULT _FillEdgeIndexBuffer();

	virtual HRESULT _FillVertex2EdgeCountBuffer();
	virtual HRESULT _FillVertex2EdgeCountSumBuffer();
	virtual HRESULT _FillVertex2EdgeBuffer();

	virtual HRESULT _FillFace2EdgeBuffer();

	virtual HRESULT _FillEdge2FaceBuffer();
	virtual HRESULT _FillEdge2FaceCountBuffer();
	virtual HRESULT _FillEdge2FaceCountSumBuffer();
	virtual HRESULT _FillVertexNormalBuffer();
public:
	CDXMesh(CDXDevice* pDevice);
	CDXMesh(const CDXMesh &rhs);
#ifndef __SWIG__
	CDXMesh& operator = (const CDXMesh &rhs);
#endif
	virtual HRESULT CopyFrom(const CDXMesh* rhs);
	virtual ~CDXMesh();

	virtual HRESULT LoadFromOBJFile(LPCWSTR path);
	virtual HRESULT SaveToOBJFile(LPCWSTR path);

	virtual HRESULT GetFaceNumber(UINT& nFace);
	virtual HRESULT GetEdgeNumber(UINT& nEdge);

	//CDXGeometry
	virtual HRESULT GetInputLayoutDesc(D3D11_INPUT_ELEMENT_DESC** layout, UINT& nElem);
	virtual HRESULT GetNumVertexBuffers(UINT* numBuffers);
	virtual HRESULT GetVertexBuffers(ID3D11Buffer** ppVertexBuffers, UINT* Strides, UINT* Offsets);
	virtual HRESULT GetIndexBuffer(ID3D11Buffer** pIndexBuffer);
	virtual HRESULT GetIndexCount(UINT& idxCount);
	virtual D3D11_PRIMITIVE_TOPOLOGY GetPrimitiveTopology() { return D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST;};
	virtual HRESULT GetInputLayout(ID3DX11Effect* pEffect, UINT techIdx, UINT passIdx, ID3D11InputLayout** ppLayout);

	//for Index Buffer
	virtual UINT GetIndexStride();
	virtual HRESULT GetIndexNumber(UINT& nIndex);
	virtual HRESULT GetValidIndexNumber(UINT& nIndex);
	virtual HRESULT ResizeIndexBuffer(UINT nIndex);
	virtual HRESULT SetIndexBufferData(const UINT* pIndex, UINT nIndex);
	virtual HRESULT CreateIndexBuffer(UINT nIndex, const void* pInitData);

	virtual HRESULT CreateMesh(UINT nVert, const D3DXVECTOR3* pVert, const D3DXVECTOR3* pVertNormal, const D3DXVECTOR2* pVertTexcoord, 
		const UINT* idxBuf, UINT nIndexCount);
	virtual HRESULT ComputeVertexNormal();
};
